﻿//===============================================================================
// Jammer.NET Development Library
// Jmr.Collections.Paging
//===============================================================================
// Copyright © Junaid Fakhruddin, Matthew Leedham and Randolph Cabral.  
// All rights reserved.
//===============================================================================
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================

using System;
using System.Collections;
using System.Collections.Generic;

namespace Jmr.Collections.Paging
{
	/// <summary>
	/// A paged list of T objects.
	/// </summary>
	/// <typeparam name="T">Type of items to page.</typeparam>
	public class Pager<T>
	{
		/// <summary>
		/// Pager constructor.
		/// </summary>
		/// <param name="items">Items to page.</param>
		public Pager(IEnumerable items)
		{
			if(_innerlist == null)
				_innerlist = new List<T>();

			foreach (var item in items)
				_innerlist.Add((T)item);

			PageSize = 100;
		}

		private void RecalculatePageCount()
		{
			if (_innerlist.Count <= PageSize)
				PageCount = 1;
			else
				PageCount = _innerlist.Count / PageSize + (((_innerlist.Count % PageSize) > 0) ? 1 : 0);
		}

		/// <summary>
		/// Pager constructor.
		/// </summary>
		/// <param name="items">Items to page.</param>
		public Pager(IEnumerable<T> items) : this((IEnumerable)items) { }

		private List<T> _innerlist { get; set; }

		/// <summary>
		/// Gets the number of pages of enumerable items. 
		/// </summary>
		public int PageCount { get; private set; }

		/// <summary>
		/// Gets the count of the enumerable items in the current page of data.
		/// </summary>
		public int CurrentPageItemCount { get; private set; }

		private int _pageSize = 0;
		/// <summary>
		/// Gets or sets the number of enumerable items per page of data. 
		/// </summary>
		public int PageSize
		{
			get
			{
				return _pageSize;
			}
			set
			{
				_pageSize = value;
				RecalculatePageCount();
			}
		}

		/// <summary>
		/// Current page index. Zero-based.
		/// </summary>
		public int PageIndex
		{
			get
			{
				return _pageIndex;
			}
		}

		/// <summary>
		/// Gets the current items for a given page.
		/// </summary>
		/// <param name="page">Page index to get.</param>
		/// <returns>Items for the requested page.</returns>
		public IEnumerable<T> GetPage(int page)
		{
			int startidx = page * PageSize;
			int endidx = startidx + PageSize;
			if (endidx > _innerlist.Count)
				endidx = Math.Abs(endidx - (endidx - _innerlist.Count));

			CurrentPageItemCount = (endidx - startidx);
			_pageIndex = page;

			for (int i = startidx; i < endidx; i++)
			{
				yield return _innerlist[i];
			}
		}
				
		private int _pageIndex = -1;

		/// <summary>
		/// Current page items.
		/// </summary>
		public IEnumerable<T> Current
		{
			get
			{
				if (_pageIndex == -1)
					throw new IndexOutOfRangeException();

				return GetPage(_pageIndex);
			}
		}

		/// <summary>
		/// Moves to the next page.
		/// </summary>
		/// <returns>Returns true on success.</returns>
		public bool MoveNext()
		{
			_pageIndex++;

			return !(_pageIndex > PageCount);
		}

		/// <summary>
		/// Resets the page index to -1.
		/// </summary>
		public void Reset()
		{
			_pageIndex = -1;
		}
	}
}
